package com.ruoyi.framework.web.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringPool;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.security.context.PermissionContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * RuoYi首创 自定义权限实现，ss取自SpringSecurity首字母
 *
 * @author ruoyi
 */
@Service("ss")
public class PermissionService {
    /**
     * 所有权限标识
     */
    private static final String ALL_PERMISSION = "*:*:*";
    /**
     * 管理员角色权限标识
     */
    private static final String SUPER_ADMIN = "admin";
    private static final String ROLE_DELIMETER = StringPool.COMMA;
    private static final String PERMISSION_DELIMETER = StringPool.COMMA;

    /**
     * 是否拥有超级管理员的权限
     *
     * @return true-拥有
     */
    private boolean hasSuperRole() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return false;
        }
        SysUser user = loginUser.getUser();
        if (Objects.isNull(user)) {
            return false;
        }
        List<SysRole> roles = user.getRoles();
        if (CollectionUtils.isEmpty(roles)) {
            return false;
        }
        return roles.parallelStream().anyMatch(SysRole::isAdmin);
    }

    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean hasPermi(String permission) {
        if (StringUtils.isBlank(permission)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return false;
        }
        if (hasSuperRole()) {
            //如果拥有超级管理员的权限
            return true;
        }
        if (CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        PermissionContextHolder.setContext(permission);
        return hasPermissions(loginUser.getPermissions(), permission);
    }

    /**
     * 验证用户是否不具备某权限，与 hasPermi逻辑相反
     *
     * @param permission 权限字符串
     * @return 用户是否不具备某权限
     */
    public boolean lacksPermi(String permission) {
        return !hasPermi(permission);
    }

    /**
     * 验证用户是否具有以下任意一个权限
     *
     * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
     * @return 用户是否具有以下任意一个权限
     */
    public boolean hasAnyPermi(String permissions) {
        if (StringUtils.isEmpty(permissions)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return false;
        }
        if (hasSuperRole()) {
            //如果用户拥有超级管理员的角色
            return true;
        }
        Set<String> permissionsByLoginUser = loginUser.getPermissions();
        if (CollectionUtils.isEmpty(permissionsByLoginUser)) {
            return false;
        }
        PermissionContextHolder.setContext(permissions);
        String[] permissionsSplit = permissions.split(PERMISSION_DELIMETER);
        return Arrays.stream(permissionsSplit)
                .parallel()
                .anyMatch(permission -> StringUtils.isNotBlank(permission)
                        && hasPermissions(permissionsByLoginUser, permission));
    }


    /**
     * 验证用户是否具有以下任意一个权限
     *
     * @param permissions 权限列表
     * @return 用户是否具有以下任意一个权限
     */
    public boolean hasAnyPermi(String... permissions) {
        if (ArrayUtil.isEmpty(permissions)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        if (hasSuperRole()) {
            return true;
        }
        PermissionContextHolder.setContext(Arrays.stream(permissions).distinct()
                .collect(Collectors.joining(PERMISSION_DELIMETER)));
        Set<String> authorities = loginUser.getPermissions();
        return Arrays.stream(permissions)
                .parallel()
                .anyMatch(permission -> Objects.nonNull(permission)
                        && hasPermissions(authorities, permission));
    }

    /**
     * 判断用户是否拥有某个角色
     *
     * @param role 角色字符串
     * @return 用户是否具备某角色
     */
    public boolean hasRole(String role) {
        if (StringUtils.isEmpty(role)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser)) {
            return false;
        }
        List<SysRole> userHasRoles = loginUser.getUser().getRoles();
        if (CollectionUtils.isEmpty(userHasRoles)) {
            return false;
        }
        return userHasRoles.parallelStream()
                .anyMatch(sysRole -> {
                    String roleKey = sysRole.getRoleKey();
                    return StringUtils.equals(StringUtils.trim(role), roleKey);
                });
    }

    /**
     * 验证用户是否不具备某角色，与 isRole逻辑相反。
     *
     * @param role 角色名称
     * @return 用户是否不具备某角色
     */
    public boolean lacksRole(String role) {
        return !hasRole(role);
    }

    /**
     * 验证用户是否具有以下任意一个角色
     *
     * @param roles 以 ROLE_DELIMETER 为分隔符的角色列表
     * @return 用户是否具有以下任意一个角色
     */
    public boolean hasAnyRoles(String roles) {
        if (StringUtils.isEmpty(roles)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (Objects.isNull(loginUser)) {
            return false;
        }
        SysUser user = loginUser.getUser();
        if (Objects.isNull(user)) {
            return false;
        }
        List<SysRole> sysRoles = user.getRoles();
        if (CollectionUtil.isEmpty(sysRoles)) {
            return false;
        }
        String[] rolesSplit = roles.split(ROLE_DELIMETER);
        return Arrays.stream(rolesSplit)
                .parallel()
                .anyMatch(this::hasRole);
    }

    /**
     * 判断是否包含权限
     *
     * @param permissions 权限列表
     * @param permission  权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String permission) {
        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
    }
}
